package com.example.redis_redisson_demo.web.redisson;

import com.example.redis_redisson_demo.common.utils.R;
import io.reactivex.Single;
import org.redisson.RedissonRx;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * 如何使用redisson提供的异步接口
 * redisson几乎为自身的每一种对象都提供了同步/异步操作接口
 */
@RestController
@RequestMapping("/redissonhowtousefuture")
public class HowToUseFuture {
    /**
     * 三种Client都有各自的同步/异步接口，根据不同情况使用
     * 现在我只会RedissonClient的同步/异步接口
     * 其文档在 https://javadoc.io/doc/org.redisson/redisson/latest/org/redisson/api/RedissonClient.html
     */
    @Autowired
    RedissonClient redissonClient;
    @Autowired
    RedissonReactiveClient redissonReactiveClient;
    @Autowired
    RedissonRxClient redissonRxClient;

    /**
     * RedissonClient提供的future类型的异步任务
     * 以商城项目中使用过得信号量 Semaphore 为例。
     *
     * @return
     */
    @RequestMapping("/futureexec")
    public R futureExec() throws ExecutionException, InterruptedException {
        RSemaphore semaphoreDemo = redissonClient.getSemaphore("SemaphoreFuture");

        /**
         * 查看RedissonClient提供的类 RSemaphore 的说明文档
         * https://javadoc.io/static/org.redisson/redisson/3.17.4/org/redisson/api/RSemaphore.html
         */

        /**
         * 在说明文档中直接提供的都是 同步方法
         * 例如 trySetPermits() / tryAcquire() / release()等等
         */
        semaphoreDemo.trySetPermits(10);

        /**
         * 在继承方法中可以看到 RSemaphore 继承了 RSemaphoreAsync中的异步方法
         * 这些异步方法就是对 RSemaphore 自身所有同步方法的异步实现
         * 例如  tryAcquireAsync()
         *
         * 这些异步方法返回 RFuture，直接把他当成是异步编排中的 Future使用即可。
         */
        RFuture<Boolean> tryAcquireAsync = semaphoreDemo.tryAcquireAsync(2);
        RFuture<Void> releaseAsync = semaphoreDemo.releaseAsync(1);

        // 完全使用Future异步编排的知识来进行编排即可
        tryAcquireAsync.whenComplete((res, exception) -> {
            System.out.println("信号量是否扣减成功:" + res);
        });

        releaseAsync.whenComplete((res, exception) -> {
            System.out.println("释放信号量锁");
        });
        // 显然上面两个异步任务谁先执行完不一定
        // 然后用get等待以下两个异步任务
        tryAcquireAsync.get();
        releaseAsync.get();


        /**
         * RSemaphore还继承了 RExpirable中关于过期时间的方法。
         *   同样继承了 RExpirableAsync 中的 异步过期时间方法。
         * RSemaphore还继承了 RObject中关于直接操作Key级别的方法。
         *   同样继承了 RObjectAsync 中的 异步直接操作Key级别的方法。
         */

        return R.ok();
    }

    /**
     * RedissonReactiveClient 同样提供异步接口。但是提供的异步对象和返回的异步类都和RedisonClient不同。
     * 例如 RedissonReactiveClient 就没有信号量这个对象，返回的是 Mono类异步类型
     */
    @RequestMapping("/monoexec")
    public R monoexec(){
        // 获取一个原子Long操作类
        RAtomicLongReactive atomicLongDemo = redissonReactiveClient.getAtomicLong("AtomicLongMono");
        Mono<Boolean> booleanMono = atomicLongDemo.compareAndSet(3, 401);
        // 暂不得知如何操作Mono类
        return R.ok();
    }

    /**
     * 同样，RedissonRxClient返回的是 Single 异步类型
     */
    @RequestMapping("flowableexec")
    public R flowable(){
        RAtomicLongRx atomicLongFlowable = redissonRxClient.getAtomicLong("AtomicLongSingle");
        Single<Boolean> booleanSingle = atomicLongFlowable.compareAndSet(3, 401);
        // 暂不得知如何操作Single类
        return R.ok();
    }

}
